/*
    <one line to give the library's name and an idea of what it does.>
    Copyright (C) 2012  Guillaume <email>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/


#ifndef msVTKOBJECT3D_H
#define msVTKOBJECT3D_H

#include <msTreeMapper.h>

#include <Eigen/Dense>

#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkCamera.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkInteractorStyleTrackballCamera.h>

#include <vtkPolyData.h>
#include <vtkPoints.h>
#include <vtkCellArray.h>
#include <vtkDoubleArray.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkLineSource.h>

#include <vtkCell.h>
#include <vtkCellData.h>
#include <vtkDataSet.h>
#include <vtkDataSetAttributes.h>
#include <vtkProperty.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataAlgorithm.h>


#include <vtkWindowToImageFilter.h>
#include <vtkPNGWriter.h>
#include <vtkJPEGWriter.h>

#include <vtkTubeFilter.h>
#include <vtkTextActor.h>
#include <vtkTextProperty.h>
#include <vtkSphereSource.h>


namespace atomism
{

  
class ms3dStructure;

class ms3dObject : public msTreeMapper
{    
      friend class ms3dStructure;
	    
private:
      //!\name from msRegister 
      //@{
      static msRegistrar Registrar;
      static bool  is3dObjectRegisteredInPython;
      static msRegister* createInstance() { return new ms3dObject; }
      //@}
      
protected:
      
      struct msColor{ double red, green, blue;
		      msColor(double r,double v,double b){red=r;blue=b;green=v;}
		      msColor(){red=0.5;blue=0.5;green=0.5;}
	              };
		      
      void registryInPython();
      
      void initialize()  {
	   msTreeMapper::initialize();
	   declareAttribute(Color.green,"Green");
           declareAttribute(Color.red,"Red");
           declareAttribute(Color.blue,"Blue");
           };
	     
      void update(){ msTreeMapper::update(); setColor(Color.red,Color.green,Color.blue); }
      
      ms3dObject():msTreeMapper(){constructVar("ms3dObject","Object3D","object3d");};
      
public:
      
      void set(vtkPolyDataAlgorithm* obj, msColor c);
      void setColor(double r,double v,double b);
      void setColor(std::string rgb);
      void show();
      
      virtual void setPosition(const Eigen::Vector3d& center){};
	    
      msColor Color;
                   
      vtkSmartPointer<vtkPolyDataAlgorithm> Object;
      vtkSmartPointer<vtkPolyDataMapper>    Mapper;
      vtkSmartPointer<vtkActor>             Actor;
 };
 
class ms3dTube : public ms3dObject
{
private:  
      //!\name from msRegister 
      //@{
      static msRegistrar Registrar;
      static bool  is3dTubeRegisteredInPython;
      static msRegister* createInstance() { return new ms3dTube; }
      //@} 
      
protected:
  
      void registryInPython();
      
      void initialize()  { ms3dObject::initialize();  
	                   declareAttribute(Rayon,"Rayon");
                           declareAttribute(Resolution,"Resolution");
	                   };
	     
      void update(){ msTreeMapper::update(); updateTube();
                     }
      
      ms3dTube() : ms3dObject(){constructVar("ms3dTube","Tube","tube");Rayon=1;Resolution=5;};
      
public:
      
      static boost::shared_ptr<ms3dTube> New() {
	     
	     boost::shared_ptr<ms3dTube> T( new ms3dTube );
	     T->initialize();T->update();
	     return T;
	     }
	     
      void setGeometry(const Eigen::Vector3d& pt1,const Eigen::Vector3d& pt2,double r);
      void setExtremities(const Eigen::Vector3d& pt1,const Eigen::Vector3d& pt2);
      void setRadius(double r);
      void setResolution(int r);
           
private:
      void updateTube();
      Eigen::Vector3d pt1;
      Eigen::Vector3d pt2;
      double Rayon;
      vtkSmartPointer<vtkLineSource> LineSource;
      vtkSmartPointer<vtkTubeFilter> Tube;
      double Resolution;
 };
 
 
class ms3dSphere : public ms3dObject  
{
private:  
      //!\name from msRegister 
      //@{
      static msRegistrar Registrar;
      static bool  is3dSphereRegisteredInPython;
      static msRegister* createInstance() { return new ms3dSphere; }
      //@}
      
protected:
  
      void registryInPython();
      
      void initialize()  { ms3dObject::initialize(); 
	                   declareAttribute(X,"X");declareAttribute(Y,"Y");declareAttribute(Z,"Z");
                           declareAttribute(Rayon,"Rayon");
                           declareAttribute(Resolution,"Resolution");
      };
	     
      void update(){ msTreeMapper::update();
                     setGeometry(X,Y,Z,Rayon);
		     setResolution(Resolution); 
		     set(Sphere,Color);
	            }
      
      ms3dSphere() :ms3dObject() {constructVar("ms3dSphere","Sphere","sphere");
                                  Sphere=vtkSmartPointer<vtkSphereSource>::New();
				  };
public:
      
      static boost::shared_ptr<ms3dSphere> New()
              {boost::shared_ptr<ms3dSphere> T( new ms3dSphere );
	       LOGGER_ENTER_FUNCTION_DBG("ms3dSphere::New(boost::shared_ptr<msUnitsManager> units)",T->getFullId());
	       T->initialize();T->update();
	       LOGGER_EXIT_FUNCTION();
	       return T;
	       }
	     
      void setGeometry(double x,double y,double z,double r);
      void setGeometry(const Eigen::Vector3d& center,double r);
      void setPosition(const Eigen::Vector3d& center);
      void setRadius(double r);
      void setResolution(int r);
           
private:
      void updateSphere();
      double X;
      double Y;
      double Z;
      double Rayon;
      
      vtkSmartPointer<vtkSphereSource> Sphere;
      
      double Resolution;
           
};
  
class msVisualizerAtoms;

class ms3dStructure: public msTreeMapper
{ 
private:  
      //!\name from msRegister 
      //@{
      static msRegistrar Registrar;
      static bool  is3dStructureRegisteredInPython;
      static msRegister* createInstance() { return new ms3dStructure; }
      //@} 
      
protected:
  
      void registryInPython();
      
      void initialize()  { msTreeMapper::initialize(); 
	                   declareChildren<ms3dObject>(Objects,"Objects");
                          };
	     
      void update(){ msTreeMapper::update(); 
	            }
	            
      ms3dStructure():msTreeMapper(){constructVar("ms3dStructure","Structure3D","structure3d");}
      
public:
          
      static boost::shared_ptr<ms3dStructure> New()
              {boost::shared_ptr<ms3dStructure> T( new ms3dStructure );
	       LOGGER_ENTER_FUNCTION_DBG("ms3dStructure::New(boost::shared_ptr<msUnitsManager> units)",T->getFullId());
	       T->initialize();T->update();
	       LOGGER_EXIT_FUNCTION();
	       return T;
	       }
	       
      void add(boost::shared_ptr<ms3dObject> obj);
      
      void resize(size_t n);
      
      void clear();
      
      void show();

      void show(vtkRenderer* Renderer);

      void savePicture(std::string file);
      
      protected:
	
      msChildren<ms3dObject> Objects;
      
      };

}

#endif // msVTKOBJECT3D_H
